#include "func.h"
#include "function.h"
#include "mysql.h"
#include "passwd.h"
#include "tcp.h"
#include "serverFunction.h"

#define WORKNUM 5
#define IPADDR "127.0.0.1"
#define USER 100
//static const int USER = 100;

int clients_list[USER] = {0};
int clientSum = 0;

int exitPipe[2];

// 启动方式：./server ip 线程池大小
int main(int argc, char* argv[])
{
    //ARGS_CHECK(argc, 3);
    pipe(exitPipe);                     // exitPipe在function.c文件里声明,用来实现线程池退出
    if(fork() != 0)                     
    {
        close(exitPipe[0]);
        signal(SIGUSR1, sigFunc);
        wait(NULL);
        exit(0);
    }
    close(exitPipe[1]);                 

    pthreadpoll_t* pthreadpoll = (pthreadpoll_t*)calloc(MAXEVENTS,sizeof(pthreadpoll_t));
    pthreadpollinit(pthreadpoll);

    int arrfd[3]={-1};
    int sfd = 0;
   // tcpInit(argv[1], "8887", &sfd);//tcp.c
    tcpInit(IPADDR, "8887", &sfd);//serverFUNCTION.c
    int ret = 0;
    int epfd = epoll_create(1);         // 生成epoll例程
    ERROR_CHECK(epfd, -1, "create");
    struct epoll_event* peventlist = (struct epoll_event*)calloc(10,sizeof(struct epoll_event));
    struct epoll_event events[2];       // 事件数组
    addfd(epfd, sfd, true);     //serverFunction.c   
    // 初始化套接字的events数组,添加需要读取数据的情况EPOLLIN和边缘触发，设置为非阻塞状态
    addfd(epfd, exitPipe[0], true);     // 同上，把用于退出的管道设置为边缘触发

    events->data.fd=sfd;
    events->events=EPOLLIN;
    epoll_ctl(epfd,EPOLL_CTL_ADD,sfd, events);

    MYSQL * conn = mysqlInit();
    char buf[64] = {0};
    memset(buf, 0, sizeof(buf));
    char username[64] = {0};
    char passwd[64] = {0};
    
    //char filename[64] = {0};
    //char order[64] = {0};
    //memset(filename, 0, sizeof(filename));
    //memset(order, 0, sizeof(order));
    int q = 0;

    while(1)
    {
        int readyNum = epoll_wait(epfd, events, 2, -1);     // 返回发生事件的文件描述符
        if(readyNum == 0)
            printf("epoll_wait timeout\n");
        else if(readyNum == -1 && errno == EINTR)
            continue;
        else if(readyNum < 0)
        {
            perror("epoll failure");
            break;
        }
        printf("epoll_events_count = %d\n", readyNum);      // 在server端打印文件描述符
        for(int i = 0; i < readyNum; ++i)
        {
            int sockfd = events[i].data.fd;
            if(sockfd == sfd)                               // 有新用户接入时
            {
                struct sockaddr_in client_address;
                socklen_t client_addrLength = sizeof(struct sockaddr_in);
                int clientfd = accept(sfd, (struct sockaddr*)&client_address, &client_addrLength);
                
                ret = recv(clientfd, buf, sizeof(buf), 0);
                    sysNote(passwd);
                char message[64];
                bzero(message, 64);
                if(strcmp(buf, "1") == 0)
                {
                    sprintf(message, "Please input username:");
                    send(clientfd, message, 64, 0);
                    ret = recv(clientfd, username, sizeof(username), 0);
                    sysNote(username);//passwd.c
                    ERROR_CHECK(ret, -1, "get username");
                  
                    bzero(message, 64);
                    sprintf(message, "Please input passwd:");
                    send(clientfd, message, 64, 0);
                    ret = recv(clientfd, passwd, sizeof(passwd), 0);
                    sysNote(passwd);
                    ERROR_CHECK(ret, -1, "get passwd");
                    
                    ret = passwdCheck(conn, username, passwd);//passwd.c
                    printf("after pwdcheck\n");

                 ////////////日志记录///////////////////////////////////////////////
                        time_t now = time(NULL);
                        struct tm *pTm = localtime(&now);
                        syslog(LOG_INFO,"%4d%2d%2d %2d:%2d:%2d user:%s  login成功！\n",
                        pTm->tm_year+1900,pTm->tm_mon+1, pTm->tm_mday,
                        pTm->tm_hour, pTm->tm_min, pTm->tm_sec,                                                                           
                        username);
          ////////////////////日志记录/////////////////////////
                    bzero(message, 64);
                    if(ret == -1) exit(0);
                    sprintf(message, "User Login success");
                    send(clientfd, message, 64, 0);
                }
                else if(strcmp(buf, "2") == 0)
                {
                    printf("register\n");
                    sprintf(message, "Please input username:");
                    send(clientfd, message, 64, 0);
                    ret = recv(clientfd, username, sizeof(username), 0);
                    sysNote(passwd);
                    ERROR_CHECK(ret, -1, "recv username");
                    
                    bzero(message, 64);
                    sprintf(message, "Please input passwd:");
                    send(clientfd, message, 64, 0);
                    recv(clientfd, passwd, sizeof(passwd), 0);
                    sysNote(passwd);
                   
                    AddUserToMysql(conn, username, passwd);  //passwd.c


                     ////////////日志记录///////////////////////////////////////////////
                        time_t now = time(NULL);
                        struct tm *pTm = localtime(&now);
                        syslog(LOG_INFO,"%4d%2d%2d %2d:%2d:%2d user:%s  注册成功！\n",
                        pTm->tm_year+1900,pTm->tm_mon+1, pTm->tm_mday,
                        pTm->tm_hour, pTm->tm_min, pTm->tm_sec,
                        username);
          ////////////////////日志记录/////////////////////////

          
                    bzero(message, 64);
                }
		
		int flags = fcntl(clientfd, F_GETFL, 0);
                flags |= O_NONBLOCK;
                fcntl(clientfd, F_GETFL, flags);
		struct epoll_event evt;
                evt.data.fd = clientfd;
                evt.events = EPOLLIN;
                epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &evt);

		printf("client connection from:%s : %d, clientfd = %d\n", inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port), clientfd);
                addfd(epfd, clientfd, true);
                clientSum++;                                            // 现有用户数+1
                clients_list[clientSum - 1] = clientfd;                 // 将文件描述符添加到现有用户数组
                printf("Add new clientfd = %d to epoll\n", clientfd);
                bzero(message, 64);
                sprintf(message, "Hello");
                int ret = send(clientfd, message, 64, 0);               // 给用户发送hello表示成功接入
                ERROR_CHECK(ret, -1, "send");
                
            }
            
/*	    
	    else if(sockfd == exitPipe[0])                              // 退出线程池时
            {
                puts("exit threadPool!");
                factory.runningFlag = 0;
                for(int j = 0;j < workerNum; ++j)
                    pthread_join(factory.tidArr[j], NULL);
                puts("done");
                exit(0);
            }
*/
            else        // 发生事件的用户不是新接入的用户
            {
                char order[64] = { 0 };
		char filename[64] = { 0 };
    		memset(filename, 0, sizeof(filename));
    		memset(order, 0, sizeof(order));
		dowork(pthreadpoll, sockfd, filename, order, epfd, conn);
            }
        }
    }
    close(sfd);
    close(epfd);
    return 0;
}

void* waitfunc(void* arg) {

	pthreadpoll_t * p = (pthreadpoll_t *)arg;
	
	while (1) 
	{
		pthread_mutex_lock(&p->mutex);
		printf("thread: pid = %d,tid = %lu is waiting\n", getpid(), pthread_self());
		pthread_cond_wait(&p->cond, &p->mutex);
		
		char buf[64] = { 0 };
		int len = recv(p->clientfd, buf, sizeof(buf), 0);
		sysNote(buf);

		if (len == 0)
		{
        		close(p->clientfd);
        		clients_list[clientSum] = 0;
        		clientSum--;
        		printf("ClientID = %d closed.\n", p->clientfd);
		}

		int u = 0, x = 0, z = 0, t = 0;//u用来辅助组成命令,x用来辅助组成文件名		
		int flag = 0;
		int mark = 0;

		for (; z < len; z++)
		{
			while (buf[z] != 32 && z < len) {//32为ASCII码中空值，遇到第一个不为' '的字符，默认其为命令
				p->order[u] = buf[z];//组成命令
				z++;
				u++;
				if (buf[z] == 32 || z == len) { //接受完命令字符，会接着遇到' '，此时就会z会被赋值为len，跳出while循环
					t = z;//这里的赋值在下面的解析文件名的for循环里会用到
					z = len;
				}
			}
			printf("order:%s\n", p->order);
		}

		//memset(filename, 0, sizeof(filename));
		for (; t < len; t++) {//有文件名的话 肯定在命令后面 接着上面
			while (buf[t] != 32 && t < len) {
				p->filename[x] = buf[t];//组成文件名
				x++;
				t++;
				if (buf[t] == 32 || t == len) {//如果等于空或者到头>
					t = len;
					flag = 1;
				}
			}
		}
		//p.filename = filename;
		printf("filename：%s\n", p->filename);

		if (p->flag == 1) // 表示线程池数组该位置有用户接入 
		{
			// char filename[19] = "The_Holy_Bible.txt";
			printf("doing work pid:%d,tid:%lu\n", getpid(), pthread_self());
			// getsFunction(p->clientfd,p->filename);
			//根据命令进入不同线程功能
			if (p->order[0] == 'c' && p->order[1] == 'd') {
				cdFunction(p->clientfd);
				printf("execute cdFunction\n");
			}
			else if (p->order[0] == 'l' && p->order[1] == 's') {
				lsFunction(p->clientfd, p->conn, p->username);
				printf("execute lsFunction\n");
			}
			else if (p->order[0] == 'p' && p->order[1] == 'w' && p->order[2] == 'd') {
				pwdFunction(p->clientfd);
				printf("execute pwdFunction\n");
			}
			else if (p->order[0] == 'p' && p->order[1] == 'u' && p->order[2] == 't' && p->order[3] == 's') {
				printf("execute putsFunction\n");
				putsFunction(p->clientfd, p->filename, p->epfd);
			}
			else if (p->order[0] == 'g' && p->order[1] == 'e' && p->order[2] == 't' && p->order[3] == 's') {
				printf("execute getsFunction\n");
				getsFunction(p->clientfd, p->filename, p->epfd);
			}
			else if (p->order[0] == 'r' && p->order[1] == 'm') {
				rmFunction(p->clientfd, buf, p->conn);
				printf("execute rmFunction\n");
			}
			else if (p->order[0] == 'm' && p->order[1] == 'k' && p->order[2] == 'd' && p->order[3] == 'i' && p->order[4] == 'r') {
				mkdirFunction(p->clientfd, p->conn, p->username, buf);
				printf("execute mkdirFunction\n");
			}
			else if (p->order[0] == 'e' && p->order[1] == 'x' && p->order[2] == 'i' && p->order[3] == 't') {
				printf("execute exitFunction\n");
				exit(0);
			}
			else {
				printf("this order is illegal.\n");
			}
			p->flag = 0;
			p->clientfd = -1;
			pthread_mutex_unlock(&p->mutex);
			printf("now pid:%d,tid%lu is end work\n", getpid(), pthread_self());
		}
		else
		{
			pthread_mutex_unlock(&p->mutex);
			printf("thread: pid = %d,tid = %lu is exited\n", getpid(), pthread_self());
			pthread_exit(NULL);
			break;
		}
	}
}

#undef WORKNUM 
#undef IPADDR
#undef MAXEVENTS
#undef USER
